﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Intelligent.OTC.Domain.Repositories;
using Intelligent.OTC.Common.UnitOfWork;
using Intelligent.OTC.Domain.DataModel;
using Intelligent.OTC.Domain;
using Intelligent.OTC.Common;
using Intelligent.OTC.Common.Utils;
using System.Threading;

namespace Intelligent.OTC.Business
{
    public class CommonService
    {
        public CommonService()
        { 
        }

        public OTCRepository CommonRep { private get; set; }

        public List<MyClass> WorkFlowPendingNum()
        {
            List<MyClass> lstPendingNum = new List<MyClass>();
            try
            {
                //Get SOA Count
                lstPendingNum.Add(this.SoaCount());

                //Get Contact Customer Count
                //lstPendingNum.Add(this.ContactCustomerCount());

                //Get Dispute Tracking Count
                lstPendingNum.Add(this.DisputeTrackingCount());

                //Get Mail View Count
                lstPendingNum.Add(this.MailViewCount());

                //Get BreakPTP View Count
                lstPendingNum.Add(this.BreakPTP());

                //Get holdCustomer
                lstPendingNum.Add(this.HoldCustomer());

                //Get Dunning Reminder
                lstPendingNum.Add(this.DunningReminder());

                return lstPendingNum;
            }
            catch (Exception ex) 
            {
                throw ex;
            }
        }

        public class MyClass
        {
            public int Key { get; set; }
            public int Value { get; set; }
        }

        private PeriodControl _per;
        //Get Current Period
        public PeriodControl per 
        {
            get
            {
                if (_per == null)
                {
                    PeroidService perService = SpringFactory.GetObjectImpl<PeroidService>("PeroidService");
                    _per = perService.getcurrentPeroid();
                    return _per;
                }
                else
                {
                    return _per;
                }
            }
        }

        private MyClass MailViewCount()
        {
            int perCount = CommonRep.GetQueryable<MailTmp>()
                            .Where(o => o.Deal == AppContext.Current.User.Deal
                                && o.Category == "Inbox"
                                && o.MailBox == AppContext.Current.User.Email).Count();


            MyClass mailView = new MyClass();
            mailView.Key = 7;
            mailView.Value = perCount;

            return mailView;
        }

        /// <summary>
        /// Get SOA Count
        /// </summary>
        /// <returns></returns>
        private MyClass SoaCount() 
        {
            ISoaService service = SpringFactory.GetObjectImpl<ISoaService>("SoaService");
            //Get SOA Count
            //update by pxc 20160307
            int SoaCount = service.GetSoaList().Where(o => (o.BatchType == 2 && o.TaskId == "") || (o.TaskId != "")).Count() + service.GetNoPaging("batch").Count();

            MyClass Soa = new MyClass();
            Soa.Key = 1;
            Soa.Value = SoaCount;
            return Soa;
        }

        /// <summary>
        /// Get Dunning Reminder Count
        /// </summary>
        /// <returns></returns>
        private MyClass DunningReminder() 
        {
            List<MyClass> lstDunningCount = new List<MyClass>();
            //Get Dunning Reminder Count

            //Old start
            //var Dunning2 = CommonRep.GetQueryable<CollectorAlert>()
            //    .Where(o => o.Eid == AppContext.Current.User.EID
            //        && o.Deal == AppContext.Current.User.Deal && o.AlertType == 2 
            //        && o.Status.ToUpper() != "Finish".ToUpper() && o.PeriodId == per.Id
            //        && o.Status.ToUpper() != "Cancelled".ToUpper() && o.ActionDate < AppContext.Current.User.Now
            //        && (o.LegalEntity != "" || o.LegalEntity != null));
            //var cus = CommonRep.GetQueryable<CollectorAlert>()
            //    .Where(o => o.Eid == AppContext.Current.User.EID
            //        && o.Deal == AppContext.Current.User.Deal && o.AlertType == 2
            //        && o.Status.ToUpper() == "Finish".ToUpper() && o.PeriodId == per.Id
            //        && o.ActionDate < AppContext.Current.User.Now
            //        && (o.LegalEntity != "" || o.LegalEntity != null)).Select(o => o.CustomerNum);
            //var Dunning3 = CommonRep.GetQueryable<CollectorAlert>()
            //    .Where(o => o.Eid == AppContext.Current.User.EID
            //        && o.Deal == AppContext.Current.User.Deal && o.AlertType == 3
            //        && o.Status.ToUpper() != "Finish".ToUpper() && o.PeriodId == per.Id
            //        && o.Status.ToUpper() != "Cancelled".ToUpper() && o.ActionDate < AppContext.Current.User.Now
            //        && cus.Contains(o.CustomerNum) && (o.LegalEntity != "" || o.LegalEntity != null));

            //int DunningCount = Dunning2.Count() + Dunning3.Count();
            //Old end
            //var r = (from dun in CommonRep.GetDbSet<CollectorAlert>()
            //         // left join customer level
            //         join cust in SpringFactory.GetObjectImpl<CustomerService>("CustomerService").GetCustomerLevel(per.Id) on new { dun.CustomerNum, dun.Deal } equals new { cust.CustomerNum, cust.Deal }
            //            into custs
            //         from cust in custs.DefaultIfEmpty()
            //         where dun.Status != "Cancelled" && dun.Status != "Finish" && (dun.AlertType == 2 || dun.AlertType == 3) && !string.IsNullOrEmpty(dun.LegalEntity) && dun.ActionDate < AppContext.Current.User.Now
            //         // inner join aging
            //         join age in CommonRep.GetQueryable<CustomerAging>().Where(o => o.Deal == AppContext.Current.User.Deal && o.RemoveFlg == "0") on new { cust.CustomerNum, cust.Deal, dun.LegalEntity } equals new { age.CustomerNum, age.Deal, age.LegalEntity }
            //         // left join hold customer table
            //         //join ch in CommonRep.GetDbSet<HoldCustomer>() on new { age.CustomerNum, age.LegalEntity } equals new { ch.CustomerNum, ch.LegalEntity }
            //         //   into custHolds
            //         //from ch in custHolds.DefaultIfEmpty()
            //         // left join SOA alert
            //         join soa in CommonRep.GetDbSet<CollectorAlert>().Where(a => a.AlertType == 1 && a.Status == "Finish") on new { cust.CustomerNum, cust.Deal } equals new { soa.CustomerNum, soa.Deal }
            //            into soas
            //         from soa in soas.DefaultIfEmpty()
            //         // left join second dunning alert
            //         join secDun in CommonRep.GetDbSet<CollectorAlert>().Where(a => a.AlertType == 2 && a.Status == "Finish") on new { cust.CustomerNum, cust.Deal, dun.LegalEntity } equals new { secDun.CustomerNum, secDun.Deal, secDun.LegalEntity }
            //            into secDuns
            //         from secDun in secDuns.DefaultIfEmpty()
            //         // EXISTS clause
            //         join inv in CommonRep.GetDbSet<InvoiceAging>().Where(inv => inv.Deal == AppContext.Current.User.Deal && (inv.TrackStates == "001" || inv.TrackStates == "002")) on new { age.CustomerNum, age.Deal } equals new { inv.CustomerNum, inv.Deal }   //&& inv.DueDate <= Period.PeriodEnd此条件去掉；&& inv.States == "004001"改为track_states
            //            into invs
            //         where invs.Any(i => dun.ReferenceNo.Contains(i.CustomerNum))
            //         select new
            //         {
            //             Id = dun.Id,
            //             //ActionDate = dun.ActionDate,
            //             //Deal = cust.Deal,
            //             //TaskId = dun.TaskId,
            //             //ReferenceNo = dun.ReferenceNo,
            //             //ProcessId = dun.ProcessId,
            //             //DunStatus = dun.Status,
            //             //CauseObjectNumber = dun.CauseObjectNumber,
            //             //BatchType = dun.BatchType,
            //             //FailedReason = dun.FailedReason,
            //             //PeriodId = dun.PeriodId,
            //             //AlertType = dun.AlertType,
            //             //CustomerNum = cust.CustomerNum,
            //             //CustomerName = cust.CustomerName,
            //             //BillGroupCode = cust.BillGroupCode,
            //             //BillGroupName = cust.BillGroupName,
            //             //ExistCont = conts.Any() ? "Y" : "N",
            //             // This is hold flag
            //             //IsHoldFlg = custHolds.Any(c => c.IsHoldFlg == "1") ? "On Hold" : "Normal",
            //             // TODO: THis is used to shown hold flag type name in UI, We will handle this in UI.
            //             //IsHoldFlg = ,
            //             //Operator = cust.Collector,
            //             // All contacts list, Another property "Contact" have logic to retrieve single line contact information.
            //             //ContactList = from c in conts
            //             //              select string.Concat(c.EmailAddress, "(", c.Name, ")"),
            //             //LegalEntity = dun.LegalEntity,
            //             //CreditLimit = age == null ? 0 : age.CreditLimit,
            //             //TotalAmt = age == null ? 0 : age.TotalAmt,
            //             //CurrentAmt = age == null ? 0 : age.CurrentAmt,
            //             //FDueOver90Amt = age == null ? 0 : (age.Due120Amt + age.Due150Amt + age.Due180Amt + age.Due210Amt + age.Due240Amt + age.Due270Amt + age.Due300Amt + age.Due330Amt + age.Due360Amt + age.DueOver360Amt),
            //             //PastDueAmt = age == null ? 0 : age.DueoverTotalAmt,
            //             //Risk = cust.Risk,
            //             //Value = cust.Value,
            //             //Class = (string.IsNullOrEmpty(cust.ValueLevel) == true ? "LV" : cust.ValueLevel) +
            //             //        (string.IsNullOrEmpty(cust.RiskLevel) == true ? "LR" : cust.RiskLevel),
            //             // Used for dunning detail page data loading.
            //             LastRemind = dun.AlertType == 2
            //                            ? (soa != null ? (soa.BatchType == 1 ? soa.CustomerNum : soa.ProcessId) : dun.CustomerNum)
            //                            : dun.AlertType == 3 ? (secDun != null ? secDun.ProcessId : null) : null
            //         });
            IDunningService service = SpringFactory.GetObjectImpl<IDunningService>("DunningReminderService");
            int DunningCount = service.GetDunningList().Where(o => (o.LastRemind != null && o.TaskId == "") || (o.TaskId != "")).Count();

            MyClass Dunning = new MyClass();
            Dunning.Key = 3;
            Dunning.Value = DunningCount;

            return Dunning;
        }

        /// <summary>
        /// Get Contact Customer Count
        /// </summary>
        /// <returns></returns>
        private MyClass ContactCustomerCount() {

            throw new NotImplementedException();
            //string[] lstMail = CommonRep.GetQueryable<MailTmp>()
            //    .Where(o => o.Type.ToUpper() == "IN".ToUpper() 
            //        && o.Status.ToUpper() == "Unprocessed".ToUpper() 
            //        && o.CustomerAssignedFlg == "1" 
            //        && o.MailBox == AppContext.Current.User.Email)
            //        .Select(o=>o.Bussiness_Reference).ToList().ToArray();

            //int contactCustomerCount = CommonRep.GetQueryable<CustomerMasterView>()
            //    .Where(o => lstMail.Contains(o.CustomerNum) 
            //        && o.Operator == AppContext.Current.User.EID && o.Deal == AppContext.Current.User.Deal).Count();

            //MyClass contactCustomer = new MyClass();
            //contactCustomer.Key = 2;
            //contactCustomer.Value = contactCustomerCount;

            //return contactCustomer;
        }

        private MyClass BreakPTP() {
            string deal = AppContext.Current.User.Deal.ToString();
            string eid = AppContext.Current.User.EID.ToString();
            DateTime dt = AppContext.Current.User.Now;
            string invoOpen = Helper.EnumToCode<InvoiceStatus>(InvoiceStatus.Open);
            string invoPTP = Helper.EnumToCode<InvoiceStatus>(InvoiceStatus.PTP);
            string invoBrPTP = Helper.EnumToCode<InvoiceStatus>(InvoiceStatus.Broken_PTP);

            var reinvo =
                 from invo in CommonRep.GetQueryable<InvoiceAging>()
                 where (invo.States == invoOpen && invo.PtpDate != null && invo.PtpDate < dt.Date)
                        || (invo.States == invoPTP && invo.PtpDate != null && invo.PtpDate < dt.Date)
                        || invo.States == invoBrPTP
                        && invo.Deal == deal
                 group invo by new { invo.CustomerNum, invo.Deal } into g
                 select new { CustomerNum = g.Key.CustomerNum, Deal = g.Key.Deal };

            var result = from cc in CommonRep.GetQueryable<CustomerCommon>()
                         where cc.Deal == deal && cc.Operator == eid
                         join invo in reinvo on cc.CustomerNum equals invo.CustomerNum
                         select cc;

            MyClass breakPTP = new MyClass();
            breakPTP.Key = 5;
            breakPTP.Value = result.Count();

            return breakPTP;
        }

        private MyClass HoldCustomer() 
        {
            string CurrentDeal = AppContext.Current.User.Deal.ToString();
            string CurrentUser = AppContext.Current.User.EID.ToString();
            DateTime CurrentTime = AppContext.Current.User.Now;

            //var res = CommonRep.GetDbSet<HoldCustomerView>().Where(
            //        cs => cs.ActionDate <= CurrentTime && cs.Deal == CurrentDeal && cs.Operator == CurrentUser
            //             && cs.DunStatus != "Finish" && cs.PeriodId == per.Id
            //    );
            string invoOpen = Helper.EnumToCode<InvoiceStatus>(InvoiceStatus.Open);
            string invoBrPTP = Helper.EnumToCode<InvoiceStatus>(InvoiceStatus.Broken_PTP);
            string invoFinRem = Helper.EnumToCode<TrackStatus>(TrackStatus.Final_Reminder_Sent);
            string invo2ndBroSent = Helper.EnumToCode<TrackStatus>(TrackStatus.Second_Broken_Sent);

            PeroidService service = SpringFactory.GetObjectImpl<PeroidService>("PeroidService");
            PeriodControl period = new PeriodControl();
            period = service.getcurrentPeroid();
            int CurrentPeriod = 0;
            if (period != null) { CurrentPeriod = period.Id; }

            var customer = CommonRep.GetDbSet<HoldCustomerView>().Where(
                    cs => cs.ActionDate <= CurrentTime && cs.Deal == CurrentDeal && cs.Operator == CurrentUser

                );

            //  2016-03-23 pxc update    states => trackstates  ################ s 
            var invoiceOpen = from invo in CommonRep.GetQueryable<InvoiceAging>()
                              where invo.Deal == CurrentDeal && invo.TrackStates == invoFinRem
                              select invo;
            //  2016-03-23 pxc update    states => trackstates  ################ e 

            var alert = from al in CommonRep.GetQueryable<CollectorAlert>()
                        where al.Deal == CurrentDeal && al.PeriodId == CurrentPeriod
                        && al.AlertType == 3 && al.Status == "Finish"
                        select al;

            var invoAlert = (from inv in invoiceOpen
                             join al in alert on new { inv.CustomerNum, inv.LegalEntity } equals new { al.CustomerNum, al.LegalEntity }
                             select new { inv.CustomerNum, inv.LegalEntity }).Union
                             (from invo in CommonRep.GetDbSet<InvoiceAging>()
                              where invo.Deal == CurrentDeal &&
                              (invo.States == invoBrPTP && invo.TrackStates == invo2ndBroSent)
                              select new { invo.CustomerNum, invo.LegalEntity });


            var res = (from cus in customer
                       join invoP in invoAlert on new { cus.CustomerNum, cus.LegalEntity } equals new { invoP.CustomerNum, invoP.LegalEntity }
                       select cus).Distinct();


            MyClass holdCustomer= new MyClass();
            holdCustomer.Key = 6;
            holdCustomer.Value = res.Count();

            return holdCustomer;
        
        }

        /// <summary>
        /// Get Dispute Tracking Count
        /// </summary>
        /// <returns></returns>
        private MyClass DisputeTrackingCount() {
            //int disTrackCount = CommonRep.GetQueryable<DisputeTrackingView>()
            //    .Where(o => o.Collector == AppContext.Current.User.EID 
            //        && o.Deal == AppContext.Current.User.Deal 
            //        && o.DisputeType == "0").Count();

            //MyClass disputeTrack = new MyClass();
            //disputeTrack.Key = 4;
            //disputeTrack.Value = disTrackCount;

            //return disputeTrack;

            var disTrackCount = (from c in CommonRep.GetQueryable<Customer>()
                                 join g in CommonRep.GetQueryable<CustomerGroupCfg>() on new { c.BillGroupCode, c.Deal } equals new { g.BillGroupCode, g.Deal }
                                 into groups
                                 from gs in groups.DefaultIfEmpty()
                                 join d in CommonRep.GetQueryable<Dispute>() on new { c.CustomerNum, c.Deal } equals new { d.CustomerNum, d.Deal }
                                 where ((gs.Collector == AppContext.Current.User.EID) || (c.Collector == AppContext.Current.User.EID))
                                 && c.RemoveFlg == "1" && c.ExcludeFlg == "0" && c.Deal == AppContext.Current.User.Deal
                                 select d.Id).Count();

            MyClass disputeTrack = new MyClass();
            disputeTrack.Key = 4;
            disputeTrack.Value = disTrackCount;

            return disputeTrack;
        }

        /// <summary>
        /// Get Call List
        /// </summary>
        /// <param name="customerNum"></param>
        /// <returns></returns>
        public IEnumerable<ContactHistory> GetCallList(string customerNum) {
            try
            {
                return CommonRep.GetQueryable<ContactHistory>()
                        .Where(o => o.CustomerNum == customerNum 
                            && o.ContactType.ToUpper() == "Call".ToUpper())
                            .OrderByDescending(o => o.Id).ToList().AsQueryable();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}
